#include "monitorservice.hpp"
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "emailservice.h"

using namespace com_oocl_monitor::service;
using namespace com_oocl_monitor::domain;
using namespace com_oocl_monitor::system;
using namespace boost::posix_time;

MonitorService::MonitorService(const FtpInfo ftpInfo, const Profile profile, const EmailConfig emailConfig, FtpPool *ftpPool, OcciPool *dbPool, RunTimeInfo *runtimeInfo)
	:Runnable(runtimeInfo), _ftpInfo(ftpInfo), _profile(profile), _emailConf(emailConfig), _ftpPool(ftpPool), _dbPool(dbPool) {
		getRunTimeInfo()->setStatus(profile._profileName, true);
}

MonitorService::~MonitorService() {
	getRunTimeInfo()->setStatus(_profile._profileName, false);
}

void MonitorService::run() {
	DataCollection *dbData = nullptr, *ftpData = nullptr;
	RunTimeInfo *_runtimeInfo = getRunTimeInfo();
	HANDLE coutMutex = OpenMutex(MUTEX_ALL_ACCESS, false, TEXT("coutMutex"));

	try {
		ftpData = getFtpData();
		dbData = getDbData();
	}
	catch (const std::exception &e) {
		WaitForSingleObject(coutMutex, INFINITE);
		std::cout << "[ERROR]" << second_clock::local_time() << " ";
		std::cout << e.what() << "\n\tProfile: " << _profile._profileName << "\n" << std::endl;
		ReleaseMutex(coutMutex);
		_runtimeInfo->setEndTime(_profile._profileName, second_clock::local_time() - minutes(_runtimeInfo->getInterval()));
		int runCount=_runtimeInfo->getRuncount(_profile._profileName);
		// 2^x sent email
		if ( runCount > 1 && ((runCount & (runCount - 1)) ==0 ) ) {
			//_runtimeInfo->resetRuncount(_profile._profileName);
			try {
				EmailService email(_emailConf, _ftpInfo, _profile);
				email.run();
			}
			catch (const std::exception &e) {
				WaitForSingleObject(coutMutex, INFINITE);
				std::cout << "Email Send Error!" << std::endl;
				ReleaseMutex(coutMutex);
			}
		}
		_runtimeInfo->incrRuncount(_profile._profileName);
		CloseHandle(coutMutex);
		delete (ftpData);
		delete (dbData);
		return;
	}

	DataCollection *diff = nullptr;
	if (_profile._dataDirection == "INBOUND") {
		diff = *ftpData - *dbData;
	}
	else {
		diff = *dbData - *ftpData;
	}
	if (diff->size() != 0) {
		if (_runtimeInfo->getRuncount(_profile._profileName) >= 2) {
			WaitForSingleObject(coutMutex, INFINITE);
			std::cout << "[Missing Files]" << second_clock::local_time() << " ";
			std::cout << "\n\tProfiles: " << _profile._profileName << "\n\tNumbers: " << diff->size() << "\n\t" << diff->toString() << "\n" << std::endl;
			ReleaseMutex(coutMutex);
			_runtimeInfo->resetRuncount(_profile._profileName);
			_runtimeInfo->setTime(_profile._profileName);
			try {
				EmailService email(_emailConf, _ftpInfo, _profile, diff->clone());
				email.run();
			}
			catch (const std::exception &e) {
				WaitForSingleObject(coutMutex, INFINITE);
				std::cout << "Email Send Error!" << std::endl;
				ReleaseMutex(coutMutex);
			}
		}
		else {
			WaitForSingleObject(coutMutex, INFINITE);
			std::cout << "[Warning]" << second_clock::local_time() << " ";
			std::cout << "\n\tProfiles: " << _profile._profileName << "\n" << std::endl;
			ReleaseMutex(coutMutex);
			_runtimeInfo->setEndTime(_profile._profileName, second_clock::local_time() - minutes(_runtimeInfo->getInterval()));
			_runtimeInfo->incrRuncount(_profile._profileName);
		}
	}
	else {
		_runtimeInfo->setTime(_profile._profileName);
		_runtimeInfo->resetRuncount(_profile._profileName);
	}
	delete(diff);
	delete(ftpData);
	delete(dbData);
	CloseHandle(coutMutex);
}

DataCollection *MonitorService::getDbData() {
	DataCollection *data = nullptr;
	data = OcciService(_dbPool).perform(_profile, getRunTimeInfo()->getStartTime(_profile._profileName), getRunTimeInfo()->getEndTime(_profile._profileName));
	return data;
}

DataCollection *MonitorService::getFtpData() {
	Profile mainProfile = _profile;
	Profile subProfile = _profile;
	DataCollection *data = nullptr;
	string uri = _profile._uri;
	if (uri != "") {
		size_t last = uri.rfind("/");
		string mainUri = uri.substr(0, last) + "/";
		//mainUri;
		mainProfile._uri = mainUri;
		DataCollection *mainUriData = FtpService(_ftpPool).perform(mainProfile, getRunTimeInfo()->getStartTime(_profile._profileName), getRunTimeInfo()->getEndTime(_profile._profileName));
		subProfile._uri = _profile._uri + "/";
		DataCollection *uriData = FtpService(_ftpPool).perform(subProfile, getRunTimeInfo()->getStartTime(_profile._profileName), getRunTimeInfo()->getEndTime(_profile._profileName));
		data = (*mainUriData) + (*uriData);
		delete(mainUriData);
		delete(uriData);
	}
	else
		data = FtpService(_ftpPool).perform(_profile, getRunTimeInfo()->getStartTime(_profile._profileName), getRunTimeInfo()->getEndTime(_profile._profileName));
	return data;
}

